package project.parser.ast.exps;

import project.environments.DynamicEnv;
import project.environments.StaticEnv;
import project.environments.Value;
import project.parser.EvalException;
import project.parser.TypecheckException;
import project.parser.ast.types.RecordType;
import project.parser.ast.types.Type;

public class FieldAccess implements Exp {
	private final Exp rec;
	private final Ident fieldId;

	public FieldAccess(Exp rec, Ident fieldId) {
		this.rec = rec;
		this.fieldId = fieldId;
	}

	@Override
	public Type typecheck(StaticEnv senv) {
		Type type = rec.typecheck(senv);
		if (!(type instanceof RecordType))
			throw new EvalException(rec.toString() + " is not a record");
		Type fieldType = ((RecordType)type).getFieldType(fieldId);
		if (fieldType == null)
			throw new TypecheckException("Field '" + fieldId + "' does not exist");
		return fieldType;
	}

	@Override
	public Value evaluate(DynamicEnv denv) {
		Value fieldValue = rec.evaluate(denv).asRecord().getFieldValue(fieldId);
		if (fieldValue == null)
			throw new EvalException("Field '" + fieldId + "' does not exist");
		return fieldValue;
	}

	@Override
	public String toString() {
		return rec.toString() + "." + fieldId;
	}

	public void set(DynamicEnv denv, Value value) {
		rec.evaluate(denv).asRecord().setFieldValue(fieldId, value);
	}

	public void set(StaticEnv senv, Type type) {
		((RecordType)rec.typecheck(senv)).setFieldType(fieldId, type);
	}
}
